home *** CD-ROM | disk | FTP | other *** search
- // WaisSource.m
- //
- // Free software created 1 Feb 1992
- // by Paul Burchard <burchard@math.utah.edu>.
- // Incorporating:
- /*
- WIDE AREA INFORMATION SERVER SOFTWARE:
- No guarantees or restrictions. See the readme file for the full standard
- disclaimer.
-
- This is part of the [NeXTstep] user-interface for the WAIS software.
- Do with it as you please.
-
- Version 0.82
- Wed Apr 24 1991
-
- jonathan@Think.COM
-
- */
- //
-
- #import "WaisSource.h"
-
- // Search path for sources.
- static id sourceFolderList;
-
- // Error panel title.
- static char *errorTitle = "WAIS Source Error!";
-
- // User information sent to remote servers.
- static NXAtom userInfo;
-
- // Decoders for WAIS structured files.
- _WaisDecoder waisDataFileDecoder[] =
- {
- { ":data-file", W_FIELD,0,0, ReadString,3, WriteString,2,
- MAX_SYMBOL_SIZE },
- { ":index-mode", W_FIELD,0,0, ReadSymbol,3, WriteSymbol,2,
- MAX_SYMBOL_SIZE },
- { NULL }
- };
-
- _WaisDecoder waisSourceDecoder[] =
- {
- { ":version", W_FIELD,0,0, ReadLongS,2, WriteLongS,2 },
- { ":ip-name", W_FIELD,0,0, ReadString,3, WriteString,2,
- MAX_SYMBOL_SIZE },
- { ":ip-address", W_FIELD,0,0, ReadString,3, WriteString,2,
- MAX_SYMBOL_SIZE },
- { ":configuration", W_FIELD,0,0, ReadString,3, NULL,0,
- MAX_SYMBOL_SIZE },
- { ":tcp-port", W_FIELD,0,0, ReadLongS,2, WriteLongS,2 },
- { ":cost", W_FIELD,0,0, ReadDoubleS,2, WriteDoubleS,2 },
- { ":cost-unit", W_FIELD,0,0, ReadSymbol,3, WriteSymbol,2,
- MAX_SYMBOL_SIZE },
- { ":database-name", W_FIELD,0,0, ReadString,3, WriteString,2,
- MAX_SYMBOL_SIZE },
- { ":description", W_FIELD,0,0, ReadString,3, WriteString,2,
- READ_BUF_SIZE },
- { ":maintainer", W_FIELD,0,0, ReadString,3, WriteString,2,
- MAX_SYMBOL_SIZE },
- { ":update-time", W_FIELD,0,0, ReadListX,1, NULL,0 },//!!!
- { ":index-list", W_LIST,
- ":include", waisDataFileDecoder },
- { NULL }
- };
-
-
- @implementation WaisSource
-
- + folderList
- {
- return sourceFolderList;
- }
-
- + setFolderList:aList
- {
- if(sourceFolderList) [sourceFolderList free];
- sourceFolderList = aList;
- return self;
- }
-
- + (const char *)defaultHomeFolder
- {
- return "/Library/WAIS/sources";
- }
-
- + (const char *)fileStructName
- {
- return ":source";
- }
-
- + (WaisDecoder)fileStructDecoder
- {
- return waisSourceDecoder;
- }
-
- + (const char *)errorTitle
- {
- return errorTitle;
- }
-
- + registerUser:(const char *)userInfoString
- {
- userInfo = NXUniqueString(userInfoString);
- return self;
- }
-
- + (BOOL)checkFileName:(const char *)fileName
- {
- if(!fileName) return NO;
- if(strlen(fileName) <= strlen(W_S_EXT)) return NO;
- if(!strstr(fileName, W_S_EXT)) return NO;
- if(0 != strcmp(W_S_EXT, strstr(fileName, W_S_EXT))) return NO;
- return YES;
- }
-
- - setKey:(const char *)aKey
- {
- const char *tail;
-
- // Set ":filename" field to be consistent with new key.
- // This is so source can function as its own source-id.
- if(![super setKey:aKey]) return nil;
- if(![self key]) return nil;
- tail = strrchr([self key], '/');
- if(tail) tail++;
- else tail = [self key];
- [self insertStringKey:":filename" value:tail];
- return self;
- }
-
- - initKey:(const char *)aKey
- {
- [super initKey:aKey];
- dataFileList = [[List alloc] init];
-
- // Redundant...
- isConnected = NO;
- connection = NULL;
- bufferLength = 0;
- listCounter = 0;
- return self;
- }
-
- - free
- {
- // If no other source needs our connection, close it.
- [self setConnected:NO];
- [[dataFileList freeObjects] free];
- return [super free];
- }
-
- - dataFileList
- {
- return dataFileList;
- }
-
- - addDataFile:data
- {
- if(![data isKindOf:[WaisDataFile class]]) return nil;
- [dataFileList addObjectIfAbsent:data];
- return self;
- }
-
- - removeDataFile:data
- {
- return [dataFileList removeObject:data];
- }
-
- - clearDataFiles
- {
- //!!! We aren't sharing data files, so free them.
- [[dataFileList freeObjects] empty];
- return self;
- }
-
- - (FILE *)connection
- {
- return connection;
- }
-
- - (BOOL)isConnected
- {
- return isConnected;
- }
-
- - (long)bufferLength
- {
- return bufferLength;
- }
-
- - copyConnection:(FILE *)theConnection length:(long)theBufferLength
- {
- connection = theConnection;
- bufferLength = theBufferLength;
- return self;
- }
-
- - setConnected:(BOOL)yn;
- {
- int i, n;
- id s;
- const char *server, *service, *otherServer, *otherService;
- char hostname[512];
- static char request[MAX_MESSAGE_LEN], response[MAX_MESSAGE_LEN];
-
- // Lock to prevent conflict with network transactions in other threads.
- [Wais lockTransaction];
-
- // When disconnecting, make sure no other source is using connection.
- if(!yn)
- {
- if(!isConnected)
- {
- connection = NULL;
- [Wais unlockTransaction];
- return self;
- }
- n = [[WaisSource waisObjectList] count];
- for(i=0; i<n; i++)
- if(self!=(s=[[WaisSource waisObjectList] objectAt:i])
- && [s isKindOf:[WaisSource class]]
- && connection==[s connection])
- break;
- if(i >= n) close_connection(connection);
- connection = NULL;
- isConnected = NO;
- [Wais unlockTransaction];
- return self;
- }
-
- // Establish connection. Don't connect to local host.
- if(isConnected) { [Wais unlockTransaction]; return self; }
- bufferLength = MAX_MESSAGE_LEN;
- gethostname(hostname, 512); hostname[512-1] = 0;
- server = [self valueForStringKey:":ip-name"];
- if(!server || strlen(server)==0)
- server = [self valueForStringKey:":ip-address"];
- if(server && (strlen(server)==0
- || strcmp(server, hostname)==0 || strcmp(server, "localhost")==0))
- server = 0;
- service = [self valueForStringKey:":tcp-port"];
- if(service && strlen(service)==0) service = 0;
- if(!server || !service) connection = NULL;
- else if(!(connection = connect_to_server(server, atoi(service))))
- {
- [Wais unlockTransaction];
- ErrorMsg(errorTitle, "Can't connect to server %s.", server);
- return nil;
- }
-
- // Send initialization message, giving info about user.
- if((bufferLength=init_connection(request, response,
- MAX_MESSAGE_LEN, connection, (userInfo?userInfo:"anonymous"))) < 0)
- {
- [Wais unlockTransaction];
- ErrorMsg(errorTitle, "Can't connect to server %s.",
- (server ? server : "localhost"));
- connection = NULL; return nil;
- }
- isConnected = YES;
-
- // Let other sources with same host and port know they're ready.
- n = [[WaisSource waisObjectList] count];
- if(server && service) for(i=0; i<n; i++)
- {
- s = [[WaisSource waisObjectList] objectAt:i];
- if(![s isKindOf:[WaisSource class]]) continue;
- if(!(otherServer=[s valueForStringKey:":ip-address"])
- && !(otherServer=[s valueForStringKey:":ip-name"]))
- continue;
- if(!(otherService=[s valueForStringKey:":tcp-port"]))
- continue;
- if(strcmp(otherServer, server)!=0
- || strcmp(otherService, service)!=0)
- continue;
- [s copyConnection:connection length:bufferLength];
- }
- [Wais unlockTransaction];
- return self;
- }
-
- - (short)readWaisStruct:(const char *)structName
- forElement:(const char *)elementName
- fromFile:(FILE *)file
- withDecoder:(WaisDecoder)theDecoder
- {
- const char *config, *tail;
- char value[STRINGSIZE+MAX_SYMBOL_SIZE];
- short check_result;
- id data;
-
- // Decode data file entry into list.
- if(0 == strcmp(elementName, ":index-list"))
- {
- data = [[WaisDataFile alloc] initKey:NULL];
- check_result = [data readWaisStruct:structName
- forElement:elementName fromFile:file withDecoder:theDecoder];
- if(check_result==FALSE || check_result==END_OF_STRUCT_OR_LIST)
- { [data free]; return check_result; }
- [dataFileList addObject:data];
- return TRUE;
- }
-
- // Else do standard read.
- check_result = [super readWaisStruct:structName
- forElement:elementName fromFile:file withDecoder:theDecoder];
-
- // Hack ugly special case of ":configuration" field.
- if(0==strcmp(structName, ":source")
- && (config=[self valueForStringKey:":configuration"]))
- {
- read_subfield(config, "IPAddress", value, STRINGSIZE);
- [self insertStringKey:":ip-address" value:value];
- read_subfield(config, "RemotePort", value, STRINGSIZE);
- [self insertStringKey:":tcp-port" value:value];
- [self insertStringKey:":configuration" value:NULL];
- }
-
- // Match key w/ info, if full src record has been read.
- if(0 == strcmp(structName, [WaisSource fileStructName]))
- {
- if(!key) [self setKey:[self valueForStringKey:":filename"]];
- else if(![self valueForStringKey:":filename"])
- {
- tail = strrchr(key, '/');
- if(tail) tail++;
- else tail = key;
- [self insertStringKey:":filename" value:tail];
- }
- }
- return check_result;
- }
-
- - readWaisFile
- {
- [self setConnected:NO];
- if(![super readWaisFile]) return nil;
- return self;
- }
-
- - (short)writeWaisStruct:(const char *)structName
- forElement:(const char *)elementName
- toFile:(FILE *)file
- withDecoder:(WaisDecoder)theDecoder
- {
- id data;
- short check_result;
-
- // Check if need next subobject in a list to extract data from.
- // The listCounter keeps track of where we are in list.
- if(0 == strcmp(elementName, ":index-list"))
- {
- data = [dataFileList objectAt:listCounter];
- if(!data) { listCounter = 0; return END_OF_STRUCT_OR_LIST; }
- else listCounter++;
- check_result = [data writeWaisStruct:structName
- forElement:elementName toFile:file withDecoder:theDecoder];
- if(check_result==FALSE || check_result==END_OF_STRUCT_OR_LIST)
- listCounter = 0;
- return check_result;
- }
-
- // Else do normal write (clearing list counter).
- listCounter = 0;
- return [super writeWaisStruct:structName
- forElement:elementName toFile:file withDecoder:theDecoder];
- }
-
- - writeWaisFile
- {
- char buf[1024];
-
- // Fill in any missing essential fields with default values first.
- if(![self valueForStringKey:":cost"]
- || strlen([self valueForStringKey:":cost"])==0)
- [self insertStringKey:":cost" value:"0.00"];
- if(![self valueForStringKey:":cost-unit"]
- || strlen([self valueForStringKey:":cost-unit"])==0)
- [self insertStringKey:":cost-unit" value:":free"];
- if(![self valueForStringKey:":description"]
- || strlen([self valueForStringKey:":description"])==0)
- {
- sprintf(buf, "Created with Objective-C WAIS by %s on %s.",
- current_user_name(), printable_time());
- [self insertStringKey:":description" value:buf];
- }
- return [super writeWaisFile];
- }
-
- @end
-
-
- @implementation WaisDataFile
-
- + (const char *)fileStructName
- {
- return ":include";
- }
-
- + (WaisDecoder)fileStructDecoder
- {
- return waisDataFileDecoder;
- }
-
- @end
-